package com.xuexiang.xui_lib.component.imageview;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.TouchEvent;

import com.xuexiang.xui_lib.util.TypedAttrUtils;

import java.io.InputStream;
/**
 * 提供为图片添加圆角、边框、剪裁到圆形或其他形状等功能。
 *
 * @author liuluming
 * @since 2021-04-08
 */
public class RadiusImageView extends Image implements Image.EstimateSizeListener, Image.DrawTask, Image.TouchEventListener {

    private int mBorderWidth;
    private boolean mIsOval = false;
    private boolean mIsCircle = false;
    private boolean mIsSelected = false;
    public boolean mSelectedMaskStatus = false;
    private Paint mBorderPaint;
    private Paint mWaveBgPaint;
    private PixelMapHolder holder;
    private RectFloat mRectF = new RectFloat();
    private int mCornerRadius;
    PixelMap mPixelMap;
    private boolean mIsTouchSelectModeEnabled = true;
    private final Matrix mShaderMatrix = new Matrix();
    private int mPosition;
    ColorFilter mSelectedColorFilter;
    private int mMaskColor;
    Color mBorderColor = new Color(Color.getIntColor("#FE6D4B"));

    /*public RadiusImageView(Context context) {
        this(context, null);
    }*/

    public RadiusImageView(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    public RadiusImageView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init();
        mBorderWidth = TypedAttrUtils.getDimensionPixelSize(attrSet, "riv_border_width", 1);
        mBorderColor = TypedAttrUtils.getColor(attrSet, "riv_border_color", mBorderColor);
        mIsCircle = TypedAttrUtils.getBoolean(attrSet, "riv_is_circle", false);
        if (!mIsCircle) {
            mIsOval = TypedAttrUtils.getBoolean(attrSet, "riv_is_oval", false);
        }
        if (!mIsOval) {
            mCornerRadius = TypedAttrUtils.getDimensionPixelSize(attrSet, "riv_corner_radius", 40);
        }
        addDrawTask(this);
        setEstimateSizeListener(this);
        setTouchEventListener(this);
    }

    private void init() {
        mWaveBgPaint = new Paint();
        mWaveBgPaint.setAntiAlias(true);
        mWaveBgPaint.setStyle(Paint.Style.FILL_STYLE);
        mWaveBgPaint.setDither(true);
        mWaveBgPaint.setFilterBitmap(true);
        mBorderPaint = new Paint();
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setStyle(Paint.Style.STROKE_STYLE);
        mBorderPaint.setColor(Color.GRAY);
        mBorderPaint.setStrokeWidth(mBorderWidth);
    }

    public void setBorderWidth(int borderWidth) {
        if (mBorderWidth != borderWidth) {
            mBorderWidth = borderWidth;
            mBorderPaint.setStrokeWidth(mBorderWidth);
            invalidate();
        }
    }

    public void setBorderColor(Color borderColor) {
        if (borderColor == mBorderColor) {
            return;
        }
        mBorderColor = borderColor;
        mBorderPaint.setColor(borderColor);
        invalidate();
    }

    public void setPixelMapToCircleImage(int resId) {
        mPixelMap = getPixelMap(resId);
        initVariable(mPixelMap);
        invalidate();
    }

    private void initVariable(PixelMap pixelMap) {
        if (pixelMap != null) {
            holder = new PixelMapHolder(pixelMap);
        }
    }

    private PixelMap getPixelMap(int resId) {
        try (InputStream inputStream = getResourceManager().getResource(resId)) {
            ImageSource imageSource = ImageSource.create(inputStream, null);
            ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
            decodingOpts.desiredSize = new Size(getWidth(), getHeight());
            decodingOpts.desiredRegion = new Rect(0, 0, 0, 0);
            return imageSource.createPixelmap(decodingOpts);
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int width = getEstimatedWidth();
        int height = getEstimatedHeight();
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (mPixelMap == null) {
            return false;
        }
        boolean widthWrapContent = widthMode == EstimateSpec.NOT_EXCEED || widthMode == EstimateSpec.UNCONSTRAINT;
        boolean heightWrapContent = heightMode == EstimateSpec.NOT_EXCEED || heightMode == EstimateSpec.UNCONSTRAINT;
        float bmWidth = mPixelMap.getImageInfo().size.width, bmHeight = mPixelMap.getImageInfo().size.height;
        float scaleX = width / bmWidth, scaleY = height / bmHeight;
        if (widthWrapContent && heightWrapContent) {
            if (scaleX >= 1 && scaleY >= 1) {
                setEstimatedSize((int) bmWidth, (int) bmHeight);
                return false;
            }

            if (scaleX >= 1) {
                setEstimatedSize((int) (bmHeight * scaleY), height);
                return false;
            }

            if (scaleY >= 1) {
                setEstimatedSize(width, (int) (bmHeight * scaleX));
                return false;
            }

            if (scaleX < scaleY) {
                setEstimatedSize(width, (int) (bmHeight * scaleX));
            } else {
                setEstimatedSize((int) (bmWidth * scaleY), height);
            }
        } else if (widthWrapContent) {
            setEstimatedSize((int) (bmWidth * scaleY), height);
        } else if (heightWrapContent) {
            setEstimatedSize(width, (int) (bmHeight * scaleX));
        }
        return false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        PixelMapShader shader = new PixelMapShader(holder, Shader.TileMode.CLAMP_TILEMODE, Shader.TileMode.CLAMP_TILEMODE);
        shader.setShaderMatrix(mShaderMatrix);
        mWaveBgPaint.setShader(shader, Paint.ShaderType.LINEAR_SHADER);
        if (getPosition() == 3) {
            if (isSelectedMaskStatus()) {
                setSelectedMaskStatus(false);
                setBorderWidth(6);
                if (getMaskColor() == Color.getIntColor("#7FEF5362")) {
                    mWaveBgPaint.setColorFilter(new ColorFilter(Color.getIntColor("#C4C8D0"), BlendMode.DARKEN));
                } else {
                    mWaveBgPaint.setColorFilter(new ColorFilter(Color.getIntColor("#7FEF5362"), BlendMode.DARKEN));
                }
            } else {
                setBorderWidth(12);
                mWaveBgPaint.setColorFilter(new ColorFilter(Color.getIntColor("#7FEF5362"), BlendMode.DARKEN));
            }
        } else {
            mWaveBgPaint.setColorFilter(mSelectedColorFilter);
        }
        drawBitmap(canvas, mBorderWidth);
        drawBorder(canvas, mBorderWidth);
    }

    private void drawBitmap(Canvas canvas, int mBorderWidth) {
        final float halfBorderWidth = mBorderWidth * 1.0f / 2;
        if (mIsCircle) {
            int center = getWidth() / 2;
            canvas.drawCircle(center, center, center - halfBorderWidth, mWaveBgPaint);
        } else {
            mRectF.left = halfBorderWidth;
            mRectF.top = halfBorderWidth;
            mRectF.right = getWidth() - halfBorderWidth;
            mRectF.bottom = getHeight() - halfBorderWidth;
            if (mIsOval) {
                canvas.drawOval(mRectF, mWaveBgPaint);
            } else {
                canvas.drawRoundRect(mRectF, mCornerRadius, mCornerRadius, mWaveBgPaint);
            }
        }
    }

    private void drawBorder(Canvas canvas, int mBorderWidth) {
        final float halfBorderWidth = mBorderWidth * 1.0f / 2;
        if (mIsCircle) {
            int radius = getWidth() / 2;
            canvas.drawCircle(radius, radius, radius - halfBorderWidth, mBorderPaint);
        } else {
            mRectF.left = halfBorderWidth;
            mRectF.top = halfBorderWidth;
            mRectF.right = getWidth() - halfBorderWidth;
            mRectF.bottom = getHeight() - halfBorderWidth;
            if (mIsOval) {
                canvas.drawOval(mRectF, mBorderPaint);
            } else {
                canvas.drawRoundRect(mRectF, mCornerRadius, mCornerRadius, mBorderPaint);
            }
        }

    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (!mIsTouchSelectModeEnabled) {
            return false;
        }
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                if (mIsSelected) {
                    setSelectedMaskStatus(true);
                    setSelectedMaskColor(1);
                    setBorderWidth(12);
                    if (getPosition() == 0) {
                        setBorderColor(new Color(Color.getIntColor("#FE6D4B")));
                    } else if (getPosition() == 1) {
                        setBorderWidth(20);
                        setBorderColor(Color.GREEN);
                    } else if (getPosition() == 3) {
                        setSelectedMaskStatus(false);
                        setBorderWidth(6);
                        setSelectedMaskColor(1);
                        setBorderColor(new Color(Color.getIntColor("#FE6D4B")));
                    }
                } else {
                    this.setAlpha(0.8f);
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                if (mIsSelected) {
                    setSelectedMaskStatus(false);
                    setSelectedMaskColor(0);
                    if (getPosition() == 0) {
                        setBorderColor(Color.BLACK);
                    } else if (getPosition() == 1) {
                        setBorderWidth(6);
                        setBorderColor(new Color(Color.getIntColor("#FE6D4B")));
                    } else if (getPosition() == 3) {
                        setSelectedMaskColor(0);
                        setSelectedMaskStatus(true);
                        setBorderWidth(6);
                        setBorderColor(new Color(Color.getIntColor("#FE6D4B")));
                    } else {
                        setBorderWidth(6);
                        setSelectedMaskColor(0);
                        setBorderColor(new Color(Color.getIntColor("#FE6D4B")));
                    }
                } else {
                    this.setAlpha(1.0f);
                }
                break;
        }
        return true;
    }

    public void setTouchSelectModeEnabled(boolean touchSelectModeEnabled) {
        mIsTouchSelectModeEnabled = touchSelectModeEnabled;
    }

    public boolean isTouchSelectModeEnabled() {
        return mIsTouchSelectModeEnabled;
    }

    public void setSelectedMaskColor(int mSelectStatus) {
        if (mSelectStatus == 1) {
            mSelectedColorFilter = new ColorFilter(Color.getIntColor("#7FEF5362"), BlendMode.DARKEN);
        } else {
            mSelectedColorFilter = new ColorFilter(Color.getIntColor("#C4C8D0"), BlendMode.DARKEN);
        }
        invalidate();
    }

    public int getPosition() {
        return mPosition;
    }

    public void setPosition(int mPosition) {
        this.mPosition = mPosition;
    }

    public void setCornerRadius(int cornerRadius) {
        if (mCornerRadius != cornerRadius) {
            mCornerRadius = cornerRadius;
            if (!mIsCircle && !mIsOval) {
                invalidate();
            }
        }
    }

    public float getCornerRadius() {
        return mCornerRadius;
    }

    public void setCircle(boolean isCircle) {
        if (mIsCircle != isCircle) {
            mIsCircle = isCircle;
            invalidate();
        }
    }

    public void setOval(boolean isOval) {
        boolean forceUpdate = false;
        if (isOval) {
            if (mIsCircle) {
                mIsCircle = false;
                forceUpdate = true;
            }

        }
        if (mIsOval != isOval || forceUpdate) {
            mIsOval = isOval;
            invalidate();
        }
    }

    public boolean isIsSelected() {
        return mIsSelected;
    }

    public void setIsSelected(boolean mIsSelected) {
        this.mIsSelected = mIsSelected;
    }

    public boolean isSelectedMaskStatus() {
        return mSelectedMaskStatus;
    }

    public void setSelectedMaskStatus(boolean mSelectedMaskStatus) {
        this.mSelectedMaskStatus = mSelectedMaskStatus;
    }

    public int getMaskColor() {
        return mMaskColor;
    }

    public void setMaskColor(int mMaskColor) {
        this.mMaskColor = mMaskColor;
        invalidate();
    }

    public ColorFilter getSelectedColorFilter() {
        return mSelectedColorFilter;
    }

    public void setSelectedColorFilter(ColorFilter mSelectedColorFilter) {
        this.mSelectedColorFilter = mSelectedColorFilter;
        invalidate();
    }
}
